﻿/*
 * Copyright © 2020, Wuxi Safover Intelligent Technology Co., Ltd. All rights reserved.
 * 
 * 无锡安永智能科技有限公司版权所有，未经许可，不得用于商业用途
 * 
 * Visit: https://www.safover.com/ 
 */

using Dna;
using log4net;
using log4net.Config;
using SciChart.Charting.Visuals;
using System;
using System.Diagnostics;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using Safover.LidarCollector.Managers;
using Safover.LidarCollector.ViewModel;

namespace Safover.LidarCollector
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        protected override void OnStartup(StartupEventArgs e)
        {
            if (!CheckIsSingleton())
            {
                Current.Shutdown();
                return;
            }

            SetupUnhandledExceptionHandling();

            try
            {
                base.OnStartup(e);

                SetupEnvironment();
                ApplicationSetup();

                DeviceManager.DeviceFactoryInstance.InitializeAll();

                Current.MainWindow = new MainWindow();
                Current.MainWindow.Closed += (s, args) => { Current.Shutdown(); };
                Current.MainWindow.Show();
            }
            catch (Exception ex)
            {
                Log.Error(ex);
            }
            
        }

        /// <summary>
        /// 使用进程级的全局互斥锁，确保Application是单实例应用
        /// </summary>
#pragma warning disable IDE0052 // Remove unread private members
        private static Mutex ApplicationMutex { get; set; }
#pragma warning restore IDE0052 // Remove unread private members

        private static bool CheckIsSingleton() 
        {
            const string applicationName = "Safover.LidarCollector.V3.0x76P49i0";
            ApplicationMutex = new Mutex(true, applicationName, out bool isNewInstance);
            if (!isNewInstance)
            {
                MessageBox.Show($"{applicationName}: 采集软件已启动!");
                return false;
            }

            return true;
        }

        /// <summary>
        /// 组件依赖注入
        /// </summary>
        private static void ApplicationSetup()
        {
            Framework.Construct<DefaultFrameworkConstruction>()
                 .AddFileLogger()
                 .AddApplicationViewModels()
                 .AddApplicationServices()
                 .Build();
        }

        private static void SetupEnvironment()
        {
            // Log4Net configuration
            XmlConfigurator.Configure();

            // TODO: 默认使用SciChart来显示通道波形数据，请配置SciChart的授权码；如果没有授权，可以替换其他控件；
            var sciChartLicenseKey = "You should set your SciChart License Key here";

            if (sciChartLicenseKey.Length < 100)
            {
                throw new NotImplementedException();
            }

            SciChartSurface.SetRuntimeLicenseKey(sciChartLicenseKey);
        }

        /// <summary>
        /// 全局异常处理机制
        /// </summary>
        private void SetupUnhandledExceptionHandling()
        {
            // Catch exceptions from all threads in the AppDomain.
            AppDomain.CurrentDomain.UnhandledException += (sender, args) =>
                ShowUnhandledException(args.ExceptionObject as Exception, "AppDomain.CurrentDomain.UnhandledException", false);

            // Catch exceptions from each AppDomain that uses a task scheduler for async operations.
            TaskScheduler.UnobservedTaskException += (sender, args) =>
                ShowUnhandledException(args.Exception, "TaskScheduler.UnobservedTaskException", false);

            // Catch exceptions from a single specific UI dispatcher thread.
            Dispatcher.UnhandledException += (sender, args) =>
            {
                // If we are debugging, let Visual Studio handle the exception and take us to the code that threw it.
                if (!Debugger.IsAttached)
                {
                    args.Handled = true;
                    ShowUnhandledException(args.Exception, "Dispatcher.UnhandledException", true);
                }
            };
        }

        private void ShowUnhandledException(Exception e, string unhandledExceptionType, bool promptUserForShutdown)
        {
            Log.Error(unhandledExceptionType, e);

            var messageBoxTitle = $"Unexpected Error Occurred: {unhandledExceptionType}";
            var messageBoxMessage = $"The following exception occurred:\n\n{e}";
            var messageBoxButtons = MessageBoxButton.OK;

            if (promptUserForShutdown)
            {
                messageBoxMessage += "\n\nNormally the app would die now. Should we let it die?";
                messageBoxButtons = MessageBoxButton.YesNo;
            }

            // Let the user decide if the app should die or not (if applicable).
            if (MessageBox.Show(messageBoxMessage, messageBoxTitle, messageBoxButtons) == MessageBoxResult.Yes)
            {
                Current.Shutdown();
            }
        }
    }
}
